import { AxiosRequestConfig, AxiosResponse, AxiosPromise } from '../types'
import { parseHeaders, processHeaders } from "../helpers/headers";
import { createError } from "../helpers/error";
import { isURLSameOrigin } from '../helpers/url';
import cookie from '../helpers/cookie';
import { isFormData } from '../helpers/util';

export default function xhr(config: AxiosRequestConfig):AxiosPromise {
  return new Promise((resolve, reject) => {
    const { data = null, url, method = 'get', headers, responseType, timeout, cancelToken, withCredentials, xsrfCookieName, xsrfHeaderName, onDownloadProgress, onUploadProgress, auth, validateStatus } = config

    const request = new XMLHttpRequest()

    
    // open
    request.open(method.toUpperCase(), url!, true)

    configureRequest()

    addEvents()

    processHeaders()

    processCancel()
    
    // send
    request.send(data)


    function configureRequest():void {
      if(responseType){
        request.responseType = responseType
      }
  
      if(timeout) {
        request.timeout = timeout
      }
  
      if(withCredentials) {
        request.withCredentials = true
      }
    }

    function addEvents():void{
      request.onerror = function handleError(){
        reject(createError('Network Error', config, null, request))
      }
  
      request.ontimeout = function handleTimeout(){
        reject(createError(`Timeout of ${timeout} ms exceeded`, config, 'ECONNABORTED', request))
      }
  
      // 上传下载进度监听
      if(onUploadProgress){
        request.onprogress = onUploadProgress
      }
      if(onDownloadProgress){
        request.upload.onprogress = onDownloadProgress
      }

      request.onreadystatechange = function handleLoad(){
        if(request.readyState !== 4){
          return
        }
        if(request.status === 0){
          return 
        }
        // 默认获取的是一行一行的 \r\n分割
        console.log('返回的', request.getAllResponseHeaders())
        const responseHeaders = parseHeaders(request.getAllResponseHeaders())
        const responseData = responseType !== 'text' ? request.response : request.responseText
        const response: AxiosResponse = {
          data: responseData,
          status: request.status,
          statusText: request.statusText,
          headers: responseHeaders,
          config,
          request
        }
        handleResponse(response)
      }
    }

    function processHeaders():void{
      // 让浏览器自动设置 content-type
      if(isFormData(data)){
        delete headers['Content-Type']
      }

      // 携带cookie
      if((withCredentials || isURLSameOrigin(url!)) && xsrfCookieName){
        const xsrfValue = cookie.read(xsrfCookieName)
        if(xsrfValue && xsrfHeaderName){
          headers[xsrfHeaderName] = xsrfValue
        }
      }

      if(auth) {
        headers['Authorization'] = 'Basic ' + btoa(auth.username + ':' + auth.password)
      }

      // 设置header
      Object.keys(headers).forEach((name) => {
        if (data === null && name.toLowerCase() === 'content-type') {
          delete headers[name]
        } else {
          request.setRequestHeader(name, headers[name])
        }
      })
    }

    function processCancel():void{
      if(cancelToken){
        // tslint:disable-next-line: no-floating-promises
        cancelToken.promise.then(reason => {
          request.abort()
          reject(reason)
        })
      }
    } 

    function handleResponse(response: AxiosResponse):void {
      if(!validateStatus || validateStatus(response.status)) {
        resolve(response)
      }else{
        reject(createError(`Request failed with status code ${response.status}`, config, null, request, response))
      }
    }
  })
}
